package io.bsly.modules.app.service.localmaster.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.bsly.common.exception.RRException;
import io.bsly.common.utils.*;
import io.bsly.config.activeMq.ActiveMqProducer;
import io.bsly.modules.app.dao.localDao.DyOrderDao;
import io.bsly.modules.app.entity.localEntity.DyCouponEntity;
import io.bsly.modules.app.entity.localEntity.DyOrderEntity;
import io.bsly.modules.app.entity.localEntity.DyProductEntity;
import io.bsly.modules.app.entity.localEntity.UserEntity;
import io.bsly.modules.app.entity.sourceEntity.*;
import io.bsly.modules.app.pojo.OrderSubmitVo;
import io.bsly.modules.app.pojo.OrderTo;
import io.bsly.modules.app.service.localmaster.DyCouponService;
import io.bsly.modules.app.service.localmaster.DyOrderService;
import io.bsly.modules.app.service.localmaster.DyProductService;
import io.bsly.modules.app.service.localmaster.UserService;
import io.bsly.modules.app.service.sourceDb.*;
import io.bsly.modules.sys.ws.WebSocket;
import io.bsly.modules.sys.ws.WsMessage;
import io.bsly.modules.sys.ws.WsMessageType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service("dyOrderService")
public class DyOrderServiceImpl extends ServiceImpl<DyOrderDao, DyOrderEntity> implements DyOrderService {

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    DyCouponService dyCouponService;
    @Autowired
    private IdUtil idUtil;
    @Autowired
    ActiveMqProducer activeMqProducer;
    @Autowired
    UserService userService;
    @Autowired
    DyProductService dyProductService;
    @Autowired
    RoomService roomService;
    @Autowired
    CanalsRoomService canalsRoomService;
    @Autowired
    RoomTypeDataService roomTypeDataService;
    @Autowired
    HotelService hotelService;
    @Autowired
    OrderService orderService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        LambdaQueryWrapper<DyOrderEntity> lambdaQueryWrapper =new LambdaQueryWrapper<>();

        if (params.containsKey("userId")&& StringUtils.isNotBlank(params.get("userId").toString())){
            lambdaQueryWrapper.eq(params.containsKey("userId"), DyOrderEntity::getUserId, params.get("userId"));
        }
        if (params.containsKey("dyCouponCode") && StringUtils.isNotBlank(params.get("dyCouponCode").toString())){
            lambdaQueryWrapper.eq(params.containsKey("dyCouponCode"), DyOrderEntity::getDyCouponCode, params.get("dyCouponCode"));
        }
        if (params.containsKey("dyOrderCode")&& StringUtils.isNotBlank(params.get("dyOrderCode").toString())){
            lambdaQueryWrapper.eq(params.containsKey("dyOrderCode"), DyOrderEntity::getDyOrderCode, params.get("dyOrderCode"));
        }

        if (params.containsKey("status")&& StringUtils.isNotBlank(params.get("status").toString())){
            String[] statuses = params.get("status").toString().split(",");
            List<String> stringList= Stream.of(statuses).collect(Collectors.toList());
            lambdaQueryWrapper.in(DyOrderEntity::getStatus,stringList );
        }
        if (params.containsKey("orderId")&& StringUtils.isNotBlank(params.get("orderId").toString())){
            lambdaQueryWrapper.eq(DyOrderEntity::getId,params.get("orderId").toString());
        }
        if (params.containsKey("hotelName")&& StringUtils.isNotBlank(params.get("hotelName").toString())){
            lambdaQueryWrapper.likeRight(DyOrderEntity::getHotelName,params.get("hotelName").toString());
        }
        if (params.containsKey("productCode")&& StringUtils.isNotBlank(params.get("productCode").toString())){
            lambdaQueryWrapper.eq(DyOrderEntity::getProductCode,params.get("productCode").toString());
        }
        if (params.containsKey("inDate")&& StringUtils.isNotBlank(params.get("inDate").toString())){
            lambdaQueryWrapper.ge(DyOrderEntity::getInDate,params.get("inDate").toString());
        }
        if (params.containsKey("outDate")&& StringUtils.isNotBlank(params.get("outDate").toString())){
            lambdaQueryWrapper.le(DyOrderEntity::getOutDate,params.get("outDate").toString());
        }
        if (params.containsKey("orderTime")&& StringUtils.isNotBlank(params.get("orderTime").toString())){
            lambdaQueryWrapper.eq(DyOrderEntity::getCreateTime,params.get("orderTime").toString());
        }

        IPage<DyOrderEntity> page = this.page( new Query<DyOrderEntity>().getPage(params),lambdaQueryWrapper  );
        return new PageUtils(page);
    }

    @Override
    public R saveOrder(OrderSubmitVo orderVo, HttpServletRequest request) {
        String orderToken = orderVo.getOrderToken();
        Long userId = (Long)request.getAttribute(Constant.USER_KEY);
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long execute = (Long)redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(Constant.USER_ORDER_TOKEN_PREFIX +userId ), orderToken);
        if (execute == 0L) {
            //令牌验证失败
            return R.error("令牌失效");
        }
        DyCouponEntity couponEntity = dyCouponService.getOne(new QueryWrapper<DyCouponEntity>() .lambda()
                .eq(DyCouponEntity::getDyCouponCode, orderVo.getDyCouponCode())
                .eq(DyCouponEntity::getDyOrderCode,orderVo.getDyOrderCode())
        );
        if (couponEntity==null){
            return  R.error("无相关的抖音订单信息");
        }
        if(couponEntity.getStatus()!=Constant.CouponStatus.ACTIVE.getValue()){
            return  R.error("抖音兑换券状态异常");
        }

        LocalDate start =orderVo.getInDate();//入住时间
        LocalDate end = orderVo.getOutDate();//离店时间
        Long stayNight = end.toEpochDay() - start.toEpochDay();

        if (stayNight.intValue()!=orderVo.getNightCount()){
            return  R.error("住宿天数异常");
        }

        //剩余间夜数比较
        Long currentTotalCount = stayNight * orderVo.getRoomCount();
        if(couponEntity.getNightCount()<currentTotalCount){
            return  R.error("超出预定间夜数");
        }

        UserEntity user = userService.getById(userId);

        LocalDateTime orderCreateTime = LocalDateTime.now();
        String orderId = getId();//获取id
        //生成本地订单
        DyOrderEntity dyOrderEntity =new DyOrderEntity();
        DyProductEntity productEntity = dyProductService.getOne(new QueryWrapper<DyProductEntity>().lambda().eq(DyProductEntity::getId, couponEntity.getProductId()));
        try {
            BeanUtils.copyProperties( orderVo ,dyOrderEntity);
            dyOrderEntity.setId(orderId);
            dyOrderEntity.setCanalsRoomId(orderVo.getCanalsRoomId());
            dyOrderEntity.setRmtOrderId(orderId);
            dyOrderEntity.setProductId(couponEntity.getProductId());
            dyOrderEntity.setDyCouponCode(couponEntity.getDyCouponCode());
            dyOrderEntity.setPrice(productEntity.getPrice().divide(new BigDecimal(productEntity.getNightCount())));
            dyOrderEntity.setProductCode(productEntity.getCode());
            dyOrderEntity.setProductName(productEntity.getName());
            dyOrderEntity.setUserId(userId.intValue());
            dyOrderEntity.setCreateTime(DateUtils.asDate(orderCreateTime));
            dyOrderEntity.setStatus(Constant.OrderStatus.WAIT.getValue());
            dyOrderEntity.setUsername(StringUtils.isNotBlank(orderVo.getUsername())?orderVo.getUsername() : StringUtils.isNotBlank(user.getUsername())?user.getUsername():"");
            dyOrderEntity.setMobile(StringUtils.isNotBlank(orderVo.getMobile())?orderVo.getMobile() : StringUtils.isNotBlank(user.getMobile())?user.getMobile():"");
            this.save(dyOrderEntity);
            log.info("用户[{}]-{} ; 订单号：{}，创建时间为：{}，预定间夜数为{}，生成本地dyOrder订单信息!",user.getId(),user.getUsername(),orderId,orderCreateTime ,currentTotalCount.intValue());
        }catch (Exception e){
            this.removeById(orderId);
            log.error("抖音订单异常01:",e);
            throw new RRException(e.getMessage());
        }

        //客服确认状态后，再变更status
        Integer nightCountBefore = couponEntity.getNightCount();
        try {
            couponEntity.setNightCount(nightCountBefore-currentTotalCount.intValue());
            boolean b = dyCouponService.updateById(couponEntity);
            log.info("用户[{}]-{} ,订单号：{}，创建时间为：{} ,BookingInfo扣减{}间夜数!",user.getId(),user.getUsername(),orderId,orderCreateTime,currentTotalCount.intValue());
        }catch (Exception e){
            //还原表记录
            this.removeById(orderId);
            log.error("抖音订单异常02:",e);
            throw new RRException(e.getMessage());
        }

        HotelEntity hotelEntity = hotelService.getById(orderVo.getHotelId());
        try {
            //生成bs订单
            OrderEntity orderEntity= new OrderEntity();
            orderEntity.setId(orderId);
            orderEntity.setCanalsOrderId(orderVo.getDyOrderCode());
            orderEntity.setHotelName(hotelEntity.getName());
            orderEntity.setLocalHotelId(hotelEntity.getId());
            orderEntity.setCanalsType("dy");
            orderEntity.setChildCanals("dy");
            orderEntity.setIsHold(false);
            orderEntity.setType(Constant.ORDER_TYPE_NEW);
            orderEntity.setStatus(Constant.ORDER_STATUS_PENDING);
            orderEntity.setNightNum(orderVo.getNightCount());
            orderEntity.setNum(orderVo.getRoomCount());
            orderEntity.setCreateTime(DateUtils.asDate(orderCreateTime));
            orderEntity.setOrderTime(DateUtils.asDate(orderCreateTime));
            orderEntity.setUpdateTime(DateUtils.asDate(orderCreateTime));
            orderEntity.setCustomerNames(StringUtils.isNotBlank(orderVo.getUsername())?orderVo.getUsername() : StringUtils.isNotBlank(user.getUsername())?user.getUsername():"");
            orderEntity.setContactTel(StringUtils.isNotBlank(orderVo.getMobile())?orderVo.getMobile() : StringUtils.isNotBlank(user.getMobile())?user.getMobile():"");
            orderEntity.setProcessed("0");
            orderEntity.setInTime(DateUtils.localDateToDate(start));
            orderEntity.setOutTime(DateUtils.localDateToDate(end));

            BigDecimal unitPrice = productEntity.getPrice().divide(new BigDecimal(productEntity.getNightCount()));
            BigDecimal total = unitPrice.multiply(new BigDecimal(currentTotalCount));
            orderEntity.setTotal(total);//订单总价格

            CanalsRoomEntity canalsRoomEntity = canalsRoomService.getById(orderVo.getCanalsRoomId());
            RoomEntity roomEntity = roomService.getById(canalsRoomEntity.getLocalRoomId());
//            RoomEntity roomEntity = roomService.getById(new QueryWrapper<RoomEntity>().lambda()
//                    .eq(RoomEntity::getHotelId, orderVo.getHotelId())
//                    .eq(RoomEntity::getRoomTypeId, orderVo.getRoomTypeId())
//                    .eq(RoomEntity::getMeal, productEntity.getMeals().toString()));
            orderEntity.setLocalRoomId(roomEntity.getId());//room表id
            orderEntity.setRoomName(canalsRoomEntity.getName());

            RoomTypeDataEntity roomTypeDataEntity = roomTypeDataService.getOne(new QueryWrapper<RoomTypeDataEntity>().lambda()
                    .eq(RoomTypeDataEntity::getRoomTypeId, roomEntity.getRoomTypeId())
                    .eq(RoomTypeDataEntity::getMeal, orderVo.getMeal())
                    .eq(RoomTypeDataEntity::getDate, orderVo.getInDate()));
            if (roomTypeDataEntity!=null){
                orderEntity.setSettlePrices(roomTypeDataEntity.getPrice().toString());//采购单价
                orderEntity.setSettleTotal(roomTypeDataEntity.getPrice().multiply(new BigDecimal(currentTotalCount)));//采购总价
            }
            orderEntity.setCity(hotelEntity.getCity());
            orderEntity.setConfirmNo(orderId);
            orderService.save(orderEntity);
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo,"sendId");
            activeMqProducer.send(Constant.NOTIFY_QUEUE_ORDER_NEW, JsonUtils.toJson(orderTo));

            //后台 socket消息
            WsMessage wsMessage = new WsMessage(WsMessageType.ORDER, orderEntity);
            WebSocket.sendToAll(wsMessage);
            log.info("用户[{}]-{} ,订单号：{}，创建时间为：{},预定间夜数：{}  ，生成源系统订单完成!",user.getId(),user.getUsername(),orderId,orderCreateTime,currentTotalCount.intValue());
        }catch (Exception e){
            log.error("抖音订单异常03:",e);
            this.removeById(orderId);
            couponEntity.setNightCount(nightCountBefore);
            dyCouponService.updateById(couponEntity);
            throw new RRException(e.getMessage());
        }
        return R.ok();
    }

    @Override
    public R cancelOrder(String orderId) {
        DyOrderEntity dyOrderEntity = this.getById(orderId);
        if (dyOrderEntity.getStatus()==1 || dyOrderEntity.getStatus()==2){
            dyOrderEntity.setStatus(Constant.OrderStatus.USER_CANCEL.getValue());
            dyOrderEntity.setConfirmTime(new Date());
            this.updateById(dyOrderEntity);
            // 返还间夜数
            DyCouponEntity couponEntity = dyCouponService.getOne(new QueryWrapper<DyCouponEntity>().lambda().eq(DyCouponEntity::getDyCouponCode, dyOrderEntity.getDyCouponCode()));
            if (couponEntity!=null){
                int returnCount = dyOrderEntity.getRoomCount() * dyOrderEntity.getNightCount();
                couponEntity.setNightCount(couponEntity.getNightCount()+returnCount);
                dyCouponService.updateById(couponEntity);
            }
            return R.ok();
        }
        return R.error("该订单无法取消！");
    }

    @Override
    public R forceCancelOrder(String orderId) {
            DyOrderEntity dyOrderEntity = this.getById(orderId);
            dyOrderEntity.setStatus(Constant.OrderStatus.USER_CANCEL.getValue());
            dyOrderEntity.setConfirmTime(new Date());
            this.updateById(dyOrderEntity);
            // 返还间夜数
            DyCouponEntity couponEntity = dyCouponService.getOne(new QueryWrapper<DyCouponEntity>().lambda().eq(DyCouponEntity::getDyCouponCode, dyOrderEntity.getDyCouponCode()));
            if (couponEntity!=null){
                int returnCount = dyOrderEntity.getRoomCount() * dyOrderEntity.getNightCount();
                couponEntity.setNightCount(couponEntity.getNightCount()+returnCount);
                //兑换券状态变更
                couponEntity.setStatus(Constant.CouponStatus.ACTIVE.getValue());
                dyCouponService.updateById(couponEntity);
            }
            return R.ok();
    }

    private String getId() {
        Random random = new Random();
        return "DY" + idUtil.getId() + random.nextInt(9);
    }


}